#include"head.h"
//简单的英文的两个转一个,不会出现两个连续的00，出现就表示已经到结尾了
//文件不区分大小写的，全部toupper，记得那个'.'是存在里面的把读出来的点删掉
void doubletosingle(char *filename, char *upperfilename, int num) {
	int j = 0;
	for (int i = 0; i < num; i = i + 2)
	{    //如果是字母，返回非零，否则返回零
		if (isalpha(filename[i]) == 0)
		{
			upperfilename[j] = filename[i];
		}
		else
			upperfilename[j] = toupper(filename[i]);
		j++;
	}
}

//把文件名存放为文件名和后缀名，后缀名大于3的，也都是用长文件名格式;含有空格的也都是长文件名
int divide(char*filename, char*prename, char*rearname) {
	int dotindex = 0;
	for (int i = 0; i < strlen(filename); i++) {
		if (filename[i] == '.')//找到分界了
		{
			dotindex = i;
			break;//假设输入是对的
		}
	}
	if (dotindex == 0)
		return -1;
	strncpy(prename, filename, dotindex);//复制前面文件名
	strncpy(rearname, &filename[dotindex + 1], strlen(filename) - dotindex - 1);
	return 0;
}

void getname(char*filepath, struct findfilepath*&head) {
	struct findfilepath *p = NULL;
	int t;
	char name[100];
	char prename[100];
	char rearname[10];
	memset(name, 0, sizeof(name));
	memset(prename, 0, sizeof(prename));
	memset(rearname, 0, sizeof(rearname));
	strncpy(name, &filepath[3], strlen(filepath)-3);
	divide(name,prename,rearname);
	printf("文件为%s  长度为%d\n", name, strlen(name));
	p = (struct findfilepath*)malloc(sizeof(struct findfilepath));
	//printf("%d  %d\n",strlen(prename),strlen(rearname));
	strcpy(p->prename, prename);
	strcpy(p->rearname, rearname);
	head=p;
	//printf("%s\n%s\n",prename,rearname);
	//printf("%s\n%s\n",p->prename,p->rearname);
}

void  createNewFile(ULONGLONG root_reladdr, HANDLE hDevice)
{
    uint8_t Buffer[512] = { 0 };
	int i=0,j=0,k=0,l=0;
	BOOL bRet;
	DWORD dwCB;
	int secotrs_per_cluster = int(the_DBR.secotrs_per_cluster);
	
	int clusters = 0;
	while(clusterChain[clusters] != 0){
		clusters++;
	}
	clusters--;
	//printf("clusters=%d\n",clusters);
	//printf("secotrs_per_cluster=%d\n",secotrs_per_cluster);
    //printf("root_reladdr=%08x\n",root_reladdr);
	LARGE_INTEGER offset;
	FILE *fp;
	fp=fopen("new.docx","wb+");
	while(clusterChain[i] != 0x0FFFFFFF){
		//printf("%d\n",clusterChain[i]);
		if (clusterChain[i+1] != 0x0FFFFFFF){
			//printf("clusterChain[i]=%d\n",clusterChain[i]);
			offset.QuadPart = root_reladdr +(ULONGLONG)((clusterChain[i]-2)*512*secotrs_per_cluster);
			//printf("offset.QuadPart=%08X\n",offset.QuadPart);
			for(j=0;j<secotrs_per_cluster;j++){
				//printf("each sector offset.QuadPart=%08X\n",offset.QuadPart);
				SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
				bRet = ReadFile(hDevice, Buffer, 512, &dwCB, NULL);
				/*for(l=0;l<32;l++){
					for(k=0;k<16;k++){
					printf("%02X ",Buffer[l*16+k]);
					}
					printf("\n");
				}*/
				fwrite(Buffer,512,1,fp);
				//printf("\n");
				offset.QuadPart += 512;
			}
			i++;
		}else{
			//printf("length=%d\n",length);
            int length2 = length / 512 + 1;//length2有效总扇区数
			//printf("length2=%d\n",length2);
			int remain_sector = length2 - (clusters-1) * secotrs_per_cluster;
			//printf("remain_sector=%d\n",remain_sector);
			//printf("%d\n",length);
            offset.QuadPart = root_reladdr +(ULONGLONG)((clusterChain[i]-2)*512*secotrs_per_cluster);
			for(j=0;j<remain_sector;j++){
				//printf("remain each sector offset.QuadPart=%08X\n",offset.QuadPart);
				SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
				bRet = ReadFile(hDevice, Buffer, 512, &dwCB, NULL);
				/*for(l=0;l<32;l++){
					for(k=0;k<16;k++){
					printf("%02X ",Buffer[l*16+k]);
					}
					printf("\n");
				}*/
				fwrite(Buffer,512,1,fp);
				//printf("\n");
				offset.QuadPart += 512;
			}
			/*SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
			bRet = ReadFile(hDevice, Buffer, 512, &dwCB, NULL);
			fwrite(Buffer,length2,1,fp);*/
			i++;
		}
	}
	fclose(fp);
}

//解析短文件名
void readfileFDT(struct shortFDT the_short_FDT, ULONGLONG FAT1_reladdr,ULONGLONG root_reladdr, HANDLE hDevice) {
	uint8_t cluster[4] = { the_short_FDT.low_cluster[0],the_short_FDT.low_cluster[1],
						the_short_FDT.high_cluster[0],the_short_FDT.high_cluster[1] };
	uint8_t leng[4] = {the_short_FDT.filelen[0],the_short_FDT.filelen[1],
	the_short_FDT.filelen[2],the_short_FDT.filelen[3]};
	uint32_t lengt = uint8to32(leng);					
	length = int(lengt);
	uint32_t firstcluster = uint8to32(cluster);//起始簇号
	printf("文件开始簇号是%08X\n", firstcluster);
	printf("簇链:\n%08X\n", firstcluster);
	clusterChain[0] = firstcluster;
	int next_sector = firstcluster / 128;//在第几个扇区？512*beg_sector
	int next_byte = (firstcluster % 128) * 4;
	uint32_t FATentry = 0;
	uint8_t Buffer[512] = { 0 };
	int needreadmore = 1;
	int seqindex = 0;
	BOOL bRet;
	DWORD dwCB;
	LARGE_INTEGER offset;
	offset.QuadPart = FAT1_reladdr + (ULONGLONG)(512 * next_sector);
	SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
	bRet = ReadFile(hDevice, Buffer, 512, &dwCB, NULL);
    int i=1;
	while (needreadmore == 1) {
		FATentry = *(uint32_t*)&Buffer[next_byte];
		printf("%08X\n", FATentry);
		clusterChain[i]=FATentry;
		i++;
		if (FATentry != 0x0FFFFFFF)//尚未结束
		{
			if (next_sector != FATentry / 128)
			{
				next_sector = FATentry / 128;
				offset.QuadPart = FAT1_reladdr + (ULONGLONG)(512 * next_sector);
				SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
				memset(Buffer, 0, 512);
				bRet = ReadFile(hDevice, Buffer, 512, &dwCB, NULL);
			}
			next_byte = (FATentry % 128) * 4;
		}
		else
			needreadmore = 0;
	}
	createNewFile(root_reladdr,hDevice);
}

/*int Compare(const char * file1, const char* file2)//对比两个文件是否相同
{
	FILE* f1, * f2;
	int size1, size2;
	unsigned char buffer1[1024], buffer2[1024];
	f1 = fopen(file1, "rb+");
	f2 = fopen(file2, "rb+");
	int isTheSame = FALSE;
	if (!f1)
		goto end;
	if (!f2)
		goto end;
	
	while (1)
	{
		size1 = fread(buffer1, 1, 1024, f1);
		size2 = fread(buffer2, 1, 1024, f2);
		//printf("%d %d\n",size1,size2);
		if (size1 != size2)
		{
			goto end;
		}
		if (size1 < 1)
			break;
		for (int i = 0; i < size1; i++)
		{
			if (buffer1[i] != buffer2[i])
			{
				//printf("%d\n",i);
				goto end;

			}
		}
	}
	isTheSame = TRUE;
end:
	if (f1)
		fclose(f1);
	if (f2)
		fclose(f2);
	return isTheSame;
}*/

void findfile(struct findfilepath * head, char* partition) {
	struct findfilepath *p = NULL;
	DISK_GEOMETRY *pdg;            // 保存磁盘参数的结构体
	BOOL bResult;                 // generic results flag
	ULONGLONG DiskSize;           // size of the drive, in bytes
	HANDLE hDevice;               // 设备句柄
	DWORD junk;                   // discard resultscc
	//printf("1111\n");
	//通过CreateFile来获得设备的句柄，打开对应的盘 
	hDevice = CreateFile(TEXT(partition), // 设备名称,这里指硬盘甚至可以是分区/扩展分区名，不区分大小写 
		GENERIC_READ,                // 读
		FILE_SHARE_READ | FILE_SHARE_WRITE,  // share mode
		NULL,             // default security attributes
		OPEN_EXISTING,    // disposition
		0,                // file attributes
		NULL);            // do not copy file attributes
	if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
	{
		printf("May be no permission!Or no such partition!\n");
		return;
	}

	//通过DeviceIoControl函数与设备进行IO，为后面做准备 
	bResult = DeviceIoControl(hDevice, // 设备的句柄
		IOCTL_DISK_GET_DRIVE_GEOMETRY, // 控制码，指明设备的类型
		NULL, 0, // no input buffer
		pdg,
		sizeof(*pdg),     // output buffer 输出，保存磁盘参数信息
		&junk,                 // # bytes returned
		(LPOVERLAPPED)NULL); // synchronous I/O
	LARGE_INTEGER offset;//读取位置 
	offset.QuadPart = (ULONGLONG)0;//0
	SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);//从这个位置开始读，DBR是FILE_BEGIN，相对位移
	DWORD dwCB;
	
	//从这个位置开始读DBR，一开始的512字节有些信息有用 
	BOOL bRet = ReadFile(hDevice, &the_DBR, 512, &dwCB, NULL);
	ULONGLONG FAT1_reladdr = (ULONGLONG)uint8to16(the_DBR.reserve_sectors) *
		(ULONGLONG)512;//得到FAT1的具体地址，但是偏移需要用相对偏移 
	ULONGLONG root_reladdr = FAT1_reladdr + (ULONGLONG)(the_DBR.FATnum) *
		(ULONGLONG)uint8to32(the_DBR.sectors_per_FAT)*(ULONGLONG)512;//根目录的起始相对位置,根目录是在第2簇
	offset.QuadPart = root_reladdr;
	SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
	memset(lpBuffer, 0, sizeof(lpBuffer));
	bRet = ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);
	//show_onesector(lpBuffer);
	char prename[101] = { 0 };
	char rearname[10] = { 0 };
	int needreadmore = 0;//在这一层目录需要继续读扇区，还没有找到文件/恰好被长文件分割了

	//1次只能读512字节整数倍,16个FDT,每个32字节
	struct FDT tempFDT[16] = { 0 }, temp_tempFDT[16] = { 0 };//后面的给长目录和文件准备
	struct shortFDT the_short_FDT = { 0 };
	struct longFDT the_long_FDT[10];
	int longfdtindex = 0;//索引项
	int index = 0;
	int tempindex = 0;
	LARGE_INTEGER temp_offset;//临时倒退找长文件项的
	int findflag = 0, mayfindflag = 0;
	p = head;
	int i = 0;
	memset(tempFDT, 0, sizeof(tempFDT));
	memcpy(tempFDT, lpBuffer, 512);
	while (findflag == 0) {
		if (tempFDT[index].content[0] == 0x00) {
			printf("\n路径错误!\n");
			return;
		}
		if ((tempFDT[index].content[11] & 0x10) == 0)//文件项,先找找文件名头四个对不对
		{
			memset(prename, 0, sizeof(prename));
			memcpy(prename, &tempFDT[index].content[0], 8);
			if (!strnicmp(prename, p->prename, 4))
			{
				memset(&the_short_FDT, 0, 32);
				memcpy(&the_short_FDT, &tempFDT[index], 32);//里面存着长目录的地址信息
				tempindex = index;//不能影响环境！！！！
				memset(prename, 0, sizeof(prename));
				memcpy(temp_tempFDT, tempFDT, sizeof(tempFDT));
				//printf("%d\n",index);
				while (1) {
					if (tempindex > 0)//如果暂时不需要倒退
					{
						tempindex--;
						if (temp_tempFDT[tempindex].content[11] == 0x0F)//的确没完
						{
							memset(&the_long_FDT[longfdtindex], 0, 32);
							memcpy(&the_long_FDT[longfdtindex], &temp_tempFDT[tempindex], 32);
							longfdtindex++;//下一个索引
						}
						else//读完了，处理字符串
						{
							for (int i = 0, k = 0; i < longfdtindex; i++)
							{
								for (int j = 0; j < 3; j++)//复制三部分
								{
									if (j == 0) {
										doubletosingle(the_long_FDT[i].name1,
											&prename[k], 10);
										k = k + 5;
									}
									else if (j == 1) {
										doubletosingle(the_long_FDT[i].name2,
											&prename[k], 12);
										k = k + 6;
									}
									else {
										doubletosingle(the_long_FDT[i].name3,
											&prename[k], 4);
										k = k + 2;
									}

								}
							}
							if (!strnicmp(prename, p->prename, strlen(p->prename)) &&
								!strnicmp(prename + strlen(p->prename) + 1, p->rearname,
									strlen(p->rearname)))
							{
								//printf("prename:%s\np->prename:%s\n",prename + strlen(p->prename) + 1,p->prename);
								findflag = 1;
								goto findlongname;
							}
							else
							{
								//printf("%d\nprename:%s\np->prename:%s\n",longfdtindex,prename,p->prename);
								findflag = 0;
								goto noyet;
							}
						}
					}
					else {//倒退回去，继续读
						tempindex = 16;//后面一进入就要做一次减法
						memset(temp_tempFDT, 0, sizeof(temp_tempFDT));
						memset(lpBuffer, 0, sizeof(lpBuffer));
						temp_offset.QuadPart = offset.QuadPart - (ULONGLONG)512;
						SetFilePointer(hDevice, temp_offset.LowPart, &temp_offset.HighPart, FILE_BEGIN);
						bRet = ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);
						memcpy(temp_tempFDT, lpBuffer, 512);
					}
				}	//end of while(1) 找长文件名目录项
			}//end of if 文件前四个相同
		noyet://这个不是，虽然文件名前四个相同
			longfdtindex = 0;
		findlongname://是的，找到了
			if (findflag == 1)
				readfileFDT(the_short_FDT, FAT1_reladdr,root_reladdr, hDevice);
		}//end of if 如果是一个短文件目录项
		if (index < 15 && findflag == 0)//没找到
			index++;
		else if (index == 15 && findflag == 0)
		{
			index = 0;
			memset(tempFDT, 0, sizeof(tempFDT));
			memset(lpBuffer, 0, sizeof(lpBuffer));
			offset.QuadPart = offset.QuadPart + (ULONGLONG)512;
			SetFilePointer(hDevice, offset.LowPart, &offset.HighPart, FILE_BEGIN);
			bRet = ReadFile(hDevice, lpBuffer, 512, &dwCB, NULL);
			memcpy(tempFDT, lpBuffer, 512);
		}
	}//end of while(findflag=0)	已经找到了，调出来
	CloseHandle(hDevice);//如果打开成功，需要关闭 
}


int main()
{
	DISK_GEOMETRY pdg;            // 保存磁盘参数的结构体
	BOOL bResult;                 // generic results flag
	ULONGLONG DiskSize;           // size of the drive, in bytes
	printf("请输入文件路径:[如E:/hello.docx]\n");
	char filepath[101] = { 0 };//文件名可能很长，方便检索文件名
	gets(filepath);
	struct findfilepath *p = NULL, *head = NULL;
	char partition[]="\\\\.\\C:";
	partition[4]=filepath[0];
	getname(filepath, head);
	findfile(head, partition);
	/*if (Compare("new.docx", filepath))
	{
		printf("文件内容相同！");
	}
	else
	{
		printf("文件内容不相同！");
	}*/
	printf("请手动检查生成的新文件与原文件是否相同\n");
	free(head);
	system("pause");
	return 0;
}
